package com.sinder.campus_prophet.utils;

import org.springframework.stereotype.Component;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * DES加解密
 * DES是一种对称加密算法，所谓对称加密算法即：加密和解密使用相同密钥的算法。DES加密算法出自IBM的研究，
 * 后来被美国政府正式采用，之后开始广泛流传，但是近些年使用越来越少，因为DES使用56位密钥，以现代计算能力，
 * 24小时内即可被破解。虽然如此，在某些简单应用中，我们还是可以使用DES加密算法，本文简单讲解DES的JAVA实现
 * 。
 * 注意：DES加密和解密过程中，密钥长度都必须是8的倍数
 */
@Component
public class DESUtils {

    /**
     * 原始密钥v2.0
     */
    private static String originKey = "sinder@1021";

    /**
     * DES加密
     */
    public static String desEncript(String clearText) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        //1.获取加密算法工具类对象  参数：转换的名称，例如 DES/CBC/PKCS5Padding。
        Cipher cipher = Cipher.getInstance("DES");
        // 对工具类对象进行初始化
        SecretKeySpec key = getKey(originKey);
        cipher.init(Cipher.ENCRYPT_MODE,key);
        // 用加密工具类对象对明文进行加密-->密文
        byte[] doFinal = cipher.doFinal(clearText.getBytes());
        //密文转换成base64编码，解决密文乱码问题
        byte[] encode = Base64.getEncoder().encode(doFinal);
        return new String(encode);
    }

    /**
     * DES算法进行解密
     */
    public static String desDecript(String cipherText) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        Cipher cipher = Cipher.getInstance("DES");
        SecretKeySpec key = getKey(originKey);
        cipher.init(Cipher.DECRYPT_MODE,key);
        //注意：因为密文是用Base64转换后的，所以在doFinal以前要用Base64转一下
        byte[] decode = Base64.getDecoder().decode(cipherText);
        byte[] doFinal = cipher.doFinal(decode);
        return new String(doFinal);
    }

    /**
     * 不论原始密钥originKey多长，我们都要形成一个8个字节的原始密钥
     * @param originKey
     * @return
     */
    private static SecretKeySpec getKey(String originKey) {
        //byte数组每个元素默认初始值位0
        byte[] buffer = new byte[8];
        //获取用户提供的原始密钥字节数组
        byte[] originKeyBytes = originKey.getBytes();
        //如果originKeyBytes.length > 8,只要8个字节，如果没有超过8个字节，就用默认初始值来填充
        for (int i = 0; i < 8 && i < originKeyBytes.length; i++) {
            buffer[i] = originKeyBytes[i];
        }
        /*
         * public SecretKeySpec(byte[] key, String algorithm)  根据给定的字节数组构造一个密钥
         * 参数 key：密钥的密钥内容。
         * 参数 algorithm：与给定的密钥内容相关联的密钥算法的名称。
         * */
        SecretKeySpec key = new SecretKeySpec(buffer, "DES");
        return key;
    }

    /**
     * 前端封装对象{}包含经过DES加密后的密码和时间戳再进行DES加密
     * 后端获取密钥直接解密获得对象数据再进行密码校验
     * @param args
     * @throws IllegalBlockSizeException
     * @throws InvalidKeyException
     * @throws BadPaddingException
     * @throws NoSuchAlgorithmException
     * @throws NoSuchPaddingException
     */
    public static void main(String[] args) throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
        Map<String, Object> map = new HashMap<>();
        map.put("password", desEncript("Xyd@&bbq.110"));
        map.put("time", new Date().getTime());
        String cipherText = desEncript(map.toString());//明文-->密文
        System.out.println("明文-->密文： " + cipherText);

        String cipherText2 = desDecript(cipherText);//密文-->明文
        System.out.println("密文-->明文： " + cipherText2);
    }
}
